#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Python 符号查找机制的单元测试
测试各种作用域和符号覆盖场景
"""

import ast
from pathlib import Path
from mcpy.ir.module import IRModule
from mcpy.symbol_table import SymbolKind
from mcpy.symbol_meta import TypeInfo, TypeKind


def build_ir_from_code(code: str) -> IRModule:
    """从 Python 代码构建 IR 模块

    Args:
        code: Python 代码字符串

    Returns:
        构建好的 IRModule
    """
    raw_ast = ast.parse(code, filename="test.py")
    ir_module = IRModule(module_full_name="test", module_path=Path("."))
    ir_module.build_from_ast(raw_ast)
    ir_module.build_symbol_cache()
    return ir_module


def make_type(type_name: str, *args: TypeInfo) -> TypeInfo:
    """创建 TypeInfo 对象的辅助函数

    Args:
        type_name: 类型名称（如 "int", "str", "list"）
        *args: 泛型参数（用于 list[int] 等）

    Returns:
        TypeInfo 对象
    """
    if args:
        # 泛型类型
        return TypeInfo(kind=TypeKind.GENERIC, name=type_name, args=list(args))
    else:
        # 基础类型
        return TypeInfo(kind=TypeKind.PRIMITIVE, name=type_name)


def find_class_node(ir_module: IRModule, class_name: str):
    """查找类节点并断言其存在

    Args:
        ir_module: IR 模块
        class_name: 类名

    Returns:
        类节点
    """
    class_node = ir_module.find_symbol_ir_node(class_name, SymbolKind.CLASS)
    assert class_node is not None, f"应该能找到类 {class_name}"
    return class_node


def find_function_node(ir_module: IRModule, func_name: str):
    """查找函数节点并断言其存在

    Args:
        ir_module: IR 模块
        func_name: 函数名

    Returns:
        函数节点
    """
    func_node = ir_module.find_symbol_ir_node(func_name, SymbolKind.FUNCTION)
    assert func_node is not None, f"应该能找到函数 {func_name}"
    return func_node


class TestSymbolLookup:
    """符号查找机制测试类"""

    def test_function_local_variables(self):
        """测试函数局部变量的符号查找"""
        code = """
def test_func(param: int) -> int:
    local_var = 10
    if param > 0:
        local_var_1 = 20
    else:
        local_var_1 = 10

    def test_func1(param: int) -> int:
        local_var_1 = 30
        nest_local_var_2 = 40
        return param + local_var_1 + nest_local_var_2

    def test_func2(param: int) -> int:
        # 这个函数使用了外层的 local_var，形成真正的闭包
        return param + local_var

    another_var: str = "hello"
    return param + local_var + local_var_1
"""
        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取函数节点
        func_node = ir_module.find_symbol_ir_node("test_func", SymbolKind.FUNCTION)
        assert func_node is not None, "应该找到函数节点"
        assert hasattr(func_node, "lookup_symbol"), "函数节点应该有 lookup_symbol 方法"

        # 测试参数查找
        param_symbol = func_node.lookup_symbol("param")
        assert param_symbol is not None, "应该能找到参数 param"
        assert param_symbol.kind == SymbolKind.PARAMETER, "param 应该是参数类型"
        if param_symbol.type_info is not None:
            assert param_symbol.type_info.name == "int", "param 类型应该是 int"

        # 测试局部变量查找
        local_var_symbol = func_node.lookup_symbol("local_var")
        assert local_var_symbol is not None, "应该能找到局部变量 local_var"
        assert local_var_symbol.kind == SymbolKind.VARIABLE, "local_var 应该是变量类型"

        # 测试在 if 分支中定义的局部变量查找
        local_var_1_symbol = func_node.lookup_symbol("local_var_1")
        assert local_var_1_symbol is not None, "应该能找到局部变量 local_var_1"
        assert (
            local_var_1_symbol.kind == SymbolKind.VARIABLE
        ), "local_var_1 应该是变量类型"

        # 测试带类型注解的局部变量
        another_var_symbol = func_node.lookup_symbol("another_var")
        assert another_var_symbol is not None, "应该能找到局部变量 another_var"
        assert (
            another_var_symbol.kind == SymbolKind.VARIABLE
        ), "another_var 应该是变量类型"

        # 测试查找嵌套函数
        test_func1_symbol = func_node.lookup_symbol("test_func1")
        assert test_func1_symbol is not None, "应该能找到嵌套函数 test_func1"
        assert (
            test_func1_symbol.kind == SymbolKind.FUNCTION
        ), "test_func1 应该是函数类型"
        assert test_func1_symbol.ir_node is not None, "test_func1 应该有 IR 节点"

        # 嵌套函数中的局部变量查找（test_func1中定义了同名的local_var_1）
        nest_local_var_1 = test_func1_symbol.ir_node.lookup_symbol("local_var_1")
        assert (
            nest_local_var_1 is not None
        ), "应该能找到 test_func1 中的局部变量 local_var_1"
        assert (
            nest_local_var_1.kind == SymbolKind.VARIABLE
        ), "local_var_1 应该是局部变量类型（在 test_func1 中定义的新变量）"

        # 测试查找另一个嵌套函数 test_func2（真正使用了外层变量的闭包）
        test_func2_symbol = func_node.lookup_symbol("test_func2")
        assert test_func2_symbol is not None, "应该能找到嵌套函数 test_func2"
        assert (
            test_func2_symbol.kind == SymbolKind.FUNCTION
        ), "test_func2 应该是函数类型"
        assert test_func2_symbol.ir_node is not None

        # 测试闭包变量查找（test_func2 中使用了外层函数的 local_var）
        closure_var = test_func2_symbol.ir_node.lookup_symbol("local_var")
        assert closure_var is not None, "应该能找到外层函数的变量 local_var"
        assert (
            closure_var.kind == SymbolKind.CLOSURE_VARIABLE
        ), "local_var 应该是闭包变量类型（在 test_func2 中被使用）"

        # 嵌套函数的函数参数查找
        assert test_func1_symbol.ir_node is not None, "test_func1 应该有 IR 节点"
        nest_param = test_func1_symbol.ir_node.lookup_symbol("param")
        assert nest_param is not None, "应该能找到嵌套函数的参数 param"
        assert nest_param.kind == SymbolKind.PARAMETER, "param 应该是参数类型"

        # 测试不存在的符号
        nonexistent_symbol = func_node.lookup_symbol("nonexistent")
        assert nonexistent_symbol is None, "不应该找到不存在的符号"

    def test_class_method_scope(self):
        """测试类方法作用域的符号查找"""
        code = """
class TestClass:
    class_attr: int = 42
    
    def method(self, param: str) -> str:
        local_var = "method_local"
        return param + local_var
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取类节点
        class_node = ir_module.find_symbol_ir_node("TestClass", SymbolKind.CLASS)
        assert class_node is not None, "应该找到类节点"
        assert hasattr(
            class_node, "get_local_symbols"
        ), "类节点应该有 get_local_symbols 方法"

        # 获取方法节点
        method_node = class_node.find_symbol_ir_node("method", SymbolKind.METHOD)
        assert method_node is not None, "应该找到方法节点"
        assert hasattr(
            method_node, "lookup_symbol"
        ), "方法节点应该有 lookup_symbol 方法"

        # 测试方法参数查找
        self_symbol = method_node.lookup_symbol("self")
        assert self_symbol is not None, "应该能找到 self 参数"
        assert self_symbol.kind == SymbolKind.PARAMETER, "self 应该是参数类型"

        param_symbol = method_node.lookup_symbol("param")
        assert param_symbol is not None, "应该能找到参数 param"
        assert param_symbol.kind == SymbolKind.PARAMETER, "param 应该是参数类型"

        # 测试方法局部变量
        local_var_symbol = method_node.lookup_symbol("local_var")
        assert local_var_symbol is not None, "应该能找到局部变量 local_var"
        assert local_var_symbol.kind == SymbolKind.VARIABLE, "local_var 应该是变量类型"

        # 测试类属性查找（通过父作用域）
        class_attr_symbol = method_node.lookup_symbol("class_attr")
        if class_attr_symbol is not None:
            assert (
                class_attr_symbol.kind == SymbolKind.ATTRIBUTE
            ), "class_attr 应该是属性类型"

    def test_module_level_symbols(self):
        """测试模块级别符号查找"""
        code = """
MODULE_CONSTANT: int = 100
global_var = "global"

def module_function() -> None:
    pass

class ModuleClass:
    pass
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 测试模块常量
        constant_symbol = ir_module.lookup_symbol("MODULE_CONSTANT")
        assert constant_symbol is not None, "应该能找到模块常量"
        assert (
            constant_symbol.kind == SymbolKind.VARIABLE
        ), "MODULE_CONSTANT 应该是变量类型"

        # 测试全局变量
        global_var_symbol = ir_module.lookup_symbol("global_var")
        assert global_var_symbol is not None, "应该能找到全局变量"
        assert (
            global_var_symbol.kind == SymbolKind.VARIABLE
        ), "global_var 应该是变量类型"

        # 测试模块函数
        func_symbol = ir_module.lookup_symbol("module_function")
        assert func_symbol is not None, "应该能找到模块函数"
        assert func_symbol.kind == SymbolKind.FUNCTION, "module_function 应该是函数类型"

        # 测试模块类
        class_symbol = ir_module.lookup_symbol("ModuleClass")
        assert class_symbol is not None, "应该能找到模块类"
        assert class_symbol.kind == SymbolKind.CLASS, "ModuleClass 应该是类类型"

    def test_scope_isolation(self):
        """测试作用域隔离"""
        code = """
def func_a(param: int) -> int:
    local_a = 10
    return param + local_a

def func_b(param: str) -> str:
    local_b = "hello"
    return param + local_b
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取两个函数节点
        func_a_node = ir_module.find_symbol_ir_node("func_a", SymbolKind.FUNCTION)
        func_b_node = ir_module.find_symbol_ir_node("func_b", SymbolKind.FUNCTION)

        assert func_a_node is not None, "应该找到函数A"
        assert func_b_node is not None, "应该找到函数B"

        # 测试作用域隔离：函数A不能访问函数B的局部变量
        local_b_in_a = func_a_node.lookup_symbol("local_b")
        assert local_b_in_a is None, "函数A不应该能找到函数B的局部变量"

        # 测试作用域隔离：函数B不能访问函数A的局部变量
        local_a_in_b = func_b_node.lookup_symbol("local_a")
        assert local_a_in_b is None, "函数B不应该能找到函数A的局部变量"

        # 但是都能找到自己的局部变量
        local_a_in_a = func_a_node.lookup_symbol("local_a")
        assert local_a_in_a is not None, "函数A应该能找到自己的局部变量"

        local_b_in_b = func_b_node.lookup_symbol("local_b")
        assert local_b_in_b is not None, "函数B应该能找到自己的局部变量"

    def test_parameter_vs_local_variable(self):
        """测试参数与局部变量的区分"""
        code = """
def test_func(x: int, y: str) -> str:
    z = x + 10
    result: str = y + str(z)
    return result
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取函数节点
        func_node = ir_module.find_symbol_ir_node("test_func", SymbolKind.FUNCTION)
        assert func_node is not None, "应该找到函数节点"

        # 测试参数
        x_symbol = func_node.lookup_symbol("x")
        assert x_symbol is not None, "应该能找到参数 x"
        assert x_symbol.kind == SymbolKind.PARAMETER, "x 应该是参数类型"

        y_symbol = func_node.lookup_symbol("y")
        assert y_symbol is not None, "应该能找到参数 y"
        assert y_symbol.kind == SymbolKind.PARAMETER, "y 应该是参数类型"

        # 测试局部变量
        z_symbol = func_node.lookup_symbol("z")
        assert z_symbol is not None, "应该能找到局部变量 z"
        assert z_symbol.kind == SymbolKind.VARIABLE, "z 应该是变量类型"

        result_symbol = func_node.lookup_symbol("result")
        assert result_symbol is not None, "应该能找到局部变量 result"
        assert result_symbol.kind == SymbolKind.VARIABLE, "result 应该是变量类型"

    def test_class_attribute_vs_method(self):
        """测试类属性与方法的区分"""
        code = """
class TestClass:
    attr1: int = 10
    attr2 = "hello"
    
    def method1(self) -> int:
        return self.attr1
    
    def method2(self, param: str) -> str:
        return param + self.attr2
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取类节点
        class_node = ir_module.find_symbol_ir_node("TestClass", SymbolKind.CLASS)
        assert class_node is not None, "应该找到类节点"

        # 测试类属性
        attr1_symbol = class_node.lookup_symbol("attr1")
        assert attr1_symbol is not None, "应该能找到类属性 attr1"
        assert attr1_symbol.kind == SymbolKind.ATTRIBUTE, "attr1 应该是属性类型"

        attr2_symbol = class_node.lookup_symbol("attr2")
        assert attr2_symbol is not None, "应该能找到类属性 attr2"
        assert attr2_symbol.kind == SymbolKind.ATTRIBUTE, "attr2 应该是属性类型"

        # 测试类方法
        method1_symbol = class_node.lookup_symbol("method1")
        assert method1_symbol is not None, "应该能找到类方法 method1"
        assert method1_symbol.kind == SymbolKind.METHOD, "method1 应该是方法类型"

        method2_symbol = class_node.lookup_symbol("method2")
        assert method2_symbol is not None, "应该能找到类方法 method2"
        assert method2_symbol.kind == SymbolKind.METHOD, "method2 应该是方法类型"

    def test_attribute_assignment_exclusion(self):
        """测试属性赋值不被误认为局部变量"""
        code = """
class TestClass:
    def __init__(self):
        self.instance_attr = 42
        local_var = 10
        self.another_attr = "hello"
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取类节点
        class_node = ir_module.find_symbol_ir_node("TestClass", SymbolKind.CLASS)
        assert class_node is not None, "应该找到类节点"

        # 获取 __init__ 方法节点
        init_method = class_node.find_symbol_ir_node("__init__", SymbolKind.METHOD)
        assert init_method is not None, "应该找到 __init__ 方法"

        # 测试真正的局部变量应该被收集
        local_var_symbol = init_method.lookup_symbol("local_var")
        assert local_var_symbol is not None, "应该能找到局部变量 local_var"
        assert local_var_symbol.kind == SymbolKind.VARIABLE, "local_var 应该是变量类型"

        # 测试实例属性应该被正确识别为类属性（通过向上查找到类作用域）
        instance_attr_symbol = init_method.lookup_symbol("instance_attr")
        assert instance_attr_symbol is not None, "应该能找到实例属性（在类作用域中）"
        assert (
            instance_attr_symbol.kind == SymbolKind.ATTRIBUTE
        ), "instance_attr 应该是属性类型"

        another_attr_symbol = init_method.lookup_symbol("another_attr")
        assert another_attr_symbol is not None, "应该能找到实例属性（在类作用域中）"
        assert (
            another_attr_symbol.kind == SymbolKind.ATTRIBUTE
        ), "another_attr 应该是属性类型"

    def test_symbol_shadowing(self):
        """测试符号遮蔽（同名符号在不同作用域）"""
        code = """
name = "module_level"

class TestClass:
    name = "class_level"
    
    def method(self):
        name = "method_level"
        return name
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 测试模块级别的符号
        module_name_symbol = ir_module.lookup_symbol("name")
        assert module_name_symbol is not None, "应该能找到模块级别的 name"
        assert (
            module_name_symbol.kind == SymbolKind.VARIABLE
        ), "模块级别的 name 应该是变量类型"

        # 获取类节点
        class_node = ir_module.find_symbol_ir_node("TestClass", SymbolKind.CLASS)
        assert class_node is not None, "应该找到类节点"

        # 测试类级别的符号
        class_name_symbol = class_node.lookup_symbol("name")
        assert class_name_symbol is not None, "应该能找到类级别的 name"
        assert (
            class_name_symbol.kind == SymbolKind.ATTRIBUTE
        ), "类级别的 name 应该是属性类型"

        # 获取方法节点
        method_node = class_node.find_symbol_ir_node("method", SymbolKind.METHOD)
        assert method_node is not None, "应该找到方法节点"

        # 测试方法级别的符号（应该遮蔽上层的同名符号）
        method_name_symbol = method_node.lookup_symbol("name")
        assert method_name_symbol is not None, "应该能找到方法级别的 name"
        assert (
            method_name_symbol.kind == SymbolKind.VARIABLE
        ), "方法级别的 name 应该是变量类型"

    def test_multiple_assignments(self):
        """测试多重赋值的符号收集"""
        code = """
def test_func():
    a = 1
    b = 2
    c = 3
    a = 10  # 重新赋值
    d, e = 4, 5  # 多重赋值（暂不支持，但不应该崩溃）
    return a + b + c
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取函数节点
        func_node = ir_module.find_symbol_ir_node("test_func", SymbolKind.FUNCTION)
        assert func_node is not None, "应该找到函数节点"

        # 测试单个变量赋值
        a_symbol = func_node.lookup_symbol("a")
        assert a_symbol is not None, "应该能找到变量 a"
        assert a_symbol.kind == SymbolKind.VARIABLE, "a 应该是变量类型"

        b_symbol = func_node.lookup_symbol("b")
        assert b_symbol is not None, "应该能找到变量 b"
        assert b_symbol.kind == SymbolKind.VARIABLE, "b 应该是变量类型"

        c_symbol = func_node.lookup_symbol("c")
        assert c_symbol is not None, "应该能找到变量 c"
        assert c_symbol.kind == SymbolKind.VARIABLE, "c 应该是变量类型"

    def test_empty_function(self):
        """测试空函数的符号查找"""
        code = """
def empty_func():
    pass

def func_with_only_param(x: int):
    pass
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 获取空函数节点
        empty_func_node = ir_module.find_symbol_ir_node(
            "empty_func", SymbolKind.FUNCTION
        )
        param_func_node = ir_module.find_symbol_ir_node(
            "func_with_only_param", SymbolKind.FUNCTION
        )

        assert empty_func_node is not None, "应该找到空函数节点"
        assert param_func_node is not None, "应该找到带参数的函数节点"

        # 测试空函数没有局部符号
        empty_symbols = list(empty_func_node.get_local_symbols())
        assert len(empty_symbols) == 0, "空函数不应该有局部符号"

        # 测试只有参数的函数
        param_symbols = list(param_func_node.get_local_symbols())
        assert len(param_symbols) == 1, "只有参数的函数应该有一个符号"
        assert param_symbols[0].name == "x", "参数名应该是 x"
        assert param_symbols[0].kind == SymbolKind.PARAMETER, "应该是参数类型"

    def test_function_has_signature(self):
        """测试 IR 函数符号包含签名信息"""
        code = """
def add(x: int, y: int) -> int:
    return x + y
"""

        ir_module = build_ir_from_code(code)

        # 查找函数符号
        symbol = ir_module.lookup_symbol("add")
        assert symbol is not None, "应该能找到 add 函数"
        assert len(symbol.signatures) > 0, "应该有签名信息"

        sig = symbol.signatures[0]
        assert sig.function_name == "add"
        assert sig.param_types == ["int", "int"]
        assert sig.return_type == "int"
        assert sig.args == ["x", "y"]

    def test_signature_matching_exact(self):
        """测试精确的签名匹配"""
        code = """
def add(x: int, y: int) -> int:
    return x + y
"""

        ir_module = build_ir_from_code(code)

        # 测试1：不带参数类型的查找
        symbol = ir_module.lookup_symbol("add")
        assert symbol is not None

        # 测试匹配 add(int, int)
        args = [make_type("int"), make_type("int")]
        matched = symbol.find_matching_signature(args)
        assert matched is not None, "应该能匹配 add(int, int)"
        assert matched.param_types == ["int", "int"]

        # 测试2：带参数类型的查找（对于本地函数，进行严格签名匹配）
        symbol_with_args = ir_module.lookup_symbol("add", func_args=args)
        assert symbol_with_args is not None, "应该能通过参数类型找到匹配的函数"
        assert symbol_with_args.name == "add"

    def test_typevar_signature_matching(self):
        """测试 TypeVar 泛型函数的签名匹配"""
        code = """
from typing import TypeVar

T = TypeVar('T')

def identity(x: T) -> T:
    return x
"""

        ir_module = build_ir_from_code(code)

        # 测试1：不带参数类型的查找
        symbol = ir_module.lookup_symbol("identity")
        assert symbol is not None
        assert len(symbol.signatures) > 0

        sig = symbol.signatures[0]
        assert "T" in sig.template_params, "应该识别 T 为模板参数"

        # 测试泛型匹配 - identity(int) 应该匹配（T 可以是任何类型）
        args_int = [make_type("int")]
        matched = symbol.find_matching_signature(args_int)
        assert matched is not None, "应该能匹配 identity(int)"

        # 测试泛型匹配 - identity(str)
        args_str = [make_type("str")]
        matched_str = symbol.find_matching_signature(args_str)
        assert matched_str is not None, "应该能匹配 identity(str)"

        # 测试2：带参数类型的查找（泛型函数应该能匹配）
        symbol_with_int = ir_module.lookup_symbol("identity", func_args=args_int)
        assert symbol_with_int is not None, "应该能通过 int 参数找到泛型函数"
        assert symbol_with_int.name == "identity"

        symbol_with_str = ir_module.lookup_symbol("identity", func_args=args_str)
        assert symbol_with_str is not None, "应该能通过 str 参数找到泛型函数"
        assert symbol_with_str.name == "identity"

    def test_lookup_symbol_without_args_types(self):
        """测试不带参数类型的 lookup_symbol（当前行为）"""
        code = """
def add(x: int, y: int) -> int:
    return x + y

def process(s: str) -> int:
    return len(s)
"""

        ir_module = build_ir_from_code(code)

        # 不带参数类型的查找
        symbol_add = ir_module.lookup_symbol("add")
        assert symbol_add is not None
        assert symbol_add.name == "add"

        symbol_process = ir_module.lookup_symbol("process")
        assert symbol_process is not None
        assert symbol_process.name == "process"

    def test_lookup_symbol_with_signature_matching(self):
        """测试 lookup_symbol 基于签名的匹配

        验证：
        1. 带 args_types 的 lookup_symbol 会进行签名匹配
        2. 签名匹配时返回符号
        3. 签名不匹配时继续在父作用域查找
        """
        code = """
def add(x: int, y: int) -> int:
    return x + y
"""

        ir_module = build_ir_from_code(code)

        # 测试1：匹配的参数类型
        args_match = [make_type("int"), make_type("int")]
        symbol = ir_module.lookup_symbol("add", func_args=args_match)
        assert symbol is not None, "签名匹配时应该能找到函数"

        # 验证签名确实匹配
        matched = symbol.find_matching_signature(args_match)
        assert matched is not None, "签名应该匹配"
        assert matched.param_types == ["int", "int"]

        # 测试2：不匹配的参数数量
        args_mismatch = [make_type("int")]  # 只有1个参数
        symbol_mismatch = ir_module.lookup_symbol("add", func_args=args_mismatch)
        # 当前由于没有其他重载，应该返回 None
        assert symbol_mismatch is None, "签名不匹配且无其他重载时应该返回 None"

    def test_signature_matching_with_builtins(self):
        """测试与 builtin 函数的签名匹配

        验证：
        1. 可以调用 builtin 函数（如 len）
        2. 签名匹配正常工作
        """
        code = """
def use_len(items: list[int]) -> int:
    return len(items)
"""

        ir_module = build_ir_from_code(code)

        # 在函数内部查找 len（应该从全局 builtin 查找）
        func_node = find_function_node(ir_module, "use_len")

        # 从函数作用域查找 len
        symbol_len = func_node.lookup_symbol("len")
        assert symbol_len is not None, "应该能找到 len 函数"
        assert len(symbol_len.signatures) > 0, "len 应该有签名信息"

    def test_method_has_signature(self):
        """测试类方法符号包含签名信息"""
        code = """
class Calculator:
    def add(self, x: int, y: int) -> int:
        return x + y
    
    def subtract(self, x: int, y: int) -> int:
        return x - y
"""

        ir_module = build_ir_from_code(code)
        class_node = find_class_node(ir_module, "Calculator")

        # 查找方法符号
        add_symbol = class_node.lookup_symbol("add")
        assert add_symbol is not None, "应该能找到 add 方法"
        assert add_symbol.kind == SymbolKind.METHOD, "add 应该是方法类型"
        assert len(add_symbol.signatures) > 0, "方法应该有签名信息"

        sig = add_symbol.signatures[0]
        assert sig.function_name == "add"
        assert sig.is_method is True, "签名应该标记为方法"
        # param_types 现在包含 self 的类型（与 builtin 一致）
        assert sig.param_types == [
            "Calculator",
            "int",
            "int",
        ], "参数类型应该是 [Calculator, int, int]（包含 self）"
        assert sig.return_type == "int"
        # self 参数应该包含在 args 中
        assert sig.args == ["self", "x", "y"]

    def test_method_signature_matching(self):
        """测试类方法的签名匹配"""
        code = """
class Calculator:
    def add(self, x: int, y: int) -> int:
        return x + y
"""

        ir_module = build_ir_from_code(code)
        class_node = find_class_node(ir_module, "Calculator")

        # 测试1：不带参数类型的查找
        add_symbol = class_node.lookup_symbol("add")
        assert add_symbol is not None

        # 测试2：签名匹配 - add(Calculator, int, int) 现在包含 self 的类型
        args = [make_type("Calculator"), make_type("int"), make_type("int")]
        matched = add_symbol.find_matching_signature(args)
        assert matched is not None, "应该能匹配 add(Calculator, int, int)"
        assert matched.param_types == ["Calculator", "int", "int"]

        # 测试3：带参数类型的查找（方法也进行严格签名匹配）
        add_symbol_with_args = class_node.lookup_symbol("add", func_args=args)
        assert add_symbol_with_args is not None, "方法签名匹配时应该能找到"
        assert add_symbol_with_args.name == "add"

        # 测试4：参数类型不匹配时找不到（self 类型错误）
        args_wrong_self = [make_type("WrongClass"), make_type("int"), make_type("int")]
        add_symbol_wrong = class_node.lookup_symbol("add", func_args=args_wrong_self)
        assert add_symbol_wrong is None, "self 类型不匹配时应该返回 None"

        # 测试5：参数类型不匹配时找不到（其他参数类型错误）
        args_wrong_params = [
            make_type("Calculator"),
            make_type("str"),
            make_type("str"),
        ]
        add_symbol_wrong2 = class_node.lookup_symbol("add", func_args=args_wrong_params)
        assert add_symbol_wrong2 is None, "参数类型不匹配时应该返回 None"

    def test_static_method_has_signature(self):
        """测试静态方法符号包含签名信息"""
        code = """
class MathUtils:
    @staticmethod
    def max_value(x: int, y: int) -> int:
        return x if x > y else y
    
    @staticmethod
    def min_value(x: int, y: int) -> int:
        return x if x < y else y
"""

        ir_module = build_ir_from_code(code)
        class_node = find_class_node(ir_module, "MathUtils")

        # 查找静态方法符号
        max_symbol = class_node.lookup_symbol("max_value")
        assert max_symbol is not None, "应该能找到静态方法 max_value"
        assert max_symbol.kind == SymbolKind.METHOD, "静态方法也是 METHOD 类型"
        assert max_symbol.is_static is True, "应该标记为静态方法"
        assert len(max_symbol.signatures) > 0, "静态方法应该有签名信息"

        sig = max_symbol.signatures[0]
        assert sig.function_name == "max_value"
        assert sig.param_types == ["int", "int"]
        assert sig.return_type == "int"
        # 静态方法不应该有 self 参数
        assert sig.args == ["x", "y"]

    def test_static_method_signature_matching(self):
        """测试静态方法的签名匹配"""
        code = """
class MathUtils:
    @staticmethod
    def max_value(x: int, y: int) -> int:
        return x if x > y else y
"""

        ir_module = build_ir_from_code(code)
        class_node = find_class_node(ir_module, "MathUtils")

        # 测试1：不带参数类型的查找
        max_symbol = class_node.lookup_symbol("max_value")
        assert max_symbol is not None

        # 测试2：签名匹配 - max_value(int, int)
        args = [make_type("int"), make_type("int")]
        matched = max_symbol.find_matching_signature(args)
        assert matched is not None, "应该能匹配 max_value(int, int)"
        assert matched.param_types == ["int", "int"]

        # 测试3：带参数类型的查找（静态方法也进行严格签名匹配）
        max_symbol_with_args = class_node.lookup_symbol("max_value", func_args=args)
        assert max_symbol_with_args is not None, "静态方法签名匹配时应该能找到"
        assert max_symbol_with_args.name == "max_value"

        # 测试4：参数类型不匹配时找不到
        args_wrong = [make_type("str"), make_type("str")]
        max_symbol_wrong = class_node.lookup_symbol("max_value", func_args=args_wrong)
        assert max_symbol_wrong is None, "静态方法签名不匹配时应该返回 None"

    def test_method_with_typevar(self):
        """测试带 TypeVar 的泛型方法签名匹配"""
        code = """
from typing import TypeVar

T = TypeVar('T')

class Container:
    def get_first(self, items: list[T]) -> T:
        return items[0]
"""

        ir_module = build_ir_from_code(code)
        class_node = find_class_node(ir_module, "Container")

        # 测试1：不带参数类型的查找
        get_first_symbol = class_node.lookup_symbol("get_first")
        assert get_first_symbol is not None
        assert len(get_first_symbol.signatures) > 0

        sig = get_first_symbol.signatures[0]
        assert "T" in sig.template_params, "应该识别 T 为模板参数"
        assert sig.is_method is True
        # param_types 应该包含 self 的类型
        assert sig.param_types[0] == "Container", "第一个参数应该是 Container（self）"

        # 测试2：签名匹配 - get_first(Container, list[int]) 现在包含 self 的类型
        args = [make_type("Container"), make_type("list", make_type("int"))]
        matched = get_first_symbol.find_matching_signature(args)
        assert matched is not None, "应该能匹配 get_first(Container, list[int])"

        # 测试3：带参数类型的查找（泛型方法也进行严格签名匹配）
        get_first_with_args = class_node.lookup_symbol("get_first", func_args=args)
        assert get_first_with_args is not None, "泛型方法签名匹配时应该能找到"
        assert get_first_with_args.name == "get_first"

        # 测试4：参数类型不匹配时找不到（参数数量错误）
        args_wrong = [
            make_type("Container"),
            make_type("list", make_type("int")),
            make_type("int"),
        ]
        get_first_wrong = class_node.lookup_symbol("get_first", func_args=args_wrong)
        assert get_first_wrong is None, "泛型方法签名不匹配时应该返回 None"

    def test_function_signature_mismatch_param_count(self):
        """测试函数参数数量不匹配时无法找到函数"""
        code = """
def add(x: int, y: int) -> int:
    return x + y
"""

        ir_module = build_ir_from_code(code)

        # 测试1：参数数量过少
        args_too_few = [make_type("int")]
        symbol_mismatch = ir_module.lookup_symbol("add", func_args=args_too_few)
        assert symbol_mismatch is None, "参数数量不匹配时应该返回 None"

        # 测试2：参数数量过多
        args_too_many = [make_type("int"), make_type("int"), make_type("int")]
        symbol_mismatch2 = ir_module.lookup_symbol("add", func_args=args_too_many)
        assert symbol_mismatch2 is None, "参数数量不匹配时应该返回 None"

        # 验证不带参数类型仍然能找到
        symbol_no_args = ir_module.lookup_symbol("add")
        assert symbol_no_args is not None, "不带参数类型应该能找到函数"

    def test_function_signature_mismatch_param_type(self):
        """测试函数参数类型不匹配时无法找到函数"""
        code = """
def process(x: int, y: str) -> str:
    return str(x) + y
"""

        ir_module = build_ir_from_code(code)

        # 测试1：第一个参数类型错误
        args_wrong_first = [make_type("str"), make_type("str")]  # 第一个应该是 int
        symbol_mismatch = ir_module.lookup_symbol("process", func_args=args_wrong_first)
        assert symbol_mismatch is None, "第一个参数类型不匹配时应该返回 None"

        # 测试2：第二个参数类型错误
        args_wrong_second = [make_type("int"), make_type("int")]  # 第二个应该是 str
        symbol_mismatch2 = ir_module.lookup_symbol(
            "process", func_args=args_wrong_second
        )
        assert symbol_mismatch2 is None, "第二个参数类型不匹配时应该返回 None"

        # 测试3：正确的参数类型
        args_correct = [make_type("int"), make_type("str")]
        symbol_match = ir_module.lookup_symbol("process", func_args=args_correct)
        assert symbol_match is not None, "参数类型匹配时应该能找到函数"
        assert symbol_match.name == "process"

    def test_typevar_function_signature_mismatch(self):
        """测试泛型函数参数数量不匹配时无法找到函数"""
        code = """
from typing import TypeVar

T = TypeVar('T')

def identity(x: T) -> T:
    return x
"""

        ir_module = build_ir_from_code(code)

        # 测试1：参数数量不匹配（0个参数）
        args_empty = []
        symbol_mismatch = ir_module.lookup_symbol("identity", func_args=args_empty)
        assert symbol_mismatch is None, "泛型函数参数数量不匹配时应该返回 None"

        # 测试2：参数数量不匹配（2个参数）
        args_two = [make_type("int"), make_type("int")]
        symbol_mismatch2 = ir_module.lookup_symbol("identity", func_args=args_two)
        assert symbol_mismatch2 is None, "泛型函数参数数量不匹配时应该返回 None"

        # 测试3：参数数量匹配（1个参数，任意类型都应该匹配）
        args_correct = [make_type("int")]
        symbol_match = ir_module.lookup_symbol("identity", func_args=args_correct)
        assert symbol_match is not None, "泛型函数参数数量匹配时应该能找到"
        assert symbol_match.name == "identity"

    def test_multiple_functions_signature_matching(self):
        """测试有多个同名函数时的签名匹配（模拟函数重载场景）"""
        code = """
def outer_func(x: int) -> int:
    def inner_func(x: int, y: int) -> int:
        return x + y
    return inner_func(x, 1)
"""

        ir_module = build_ir_from_code(code)

        # 在模块级别查找 outer_func（1个参数）
        args_one = [make_type("int")]
        symbol_outer = ir_module.lookup_symbol("outer_func", func_args=args_one)
        assert symbol_outer is not None, "应该能找到 outer_func(int)"
        assert symbol_outer.name == "outer_func"

        # 在模块级别查找 inner_func 应该找不到（在嵌套作用域）
        args_two = [make_type("int"), make_type("int")]
        symbol_inner_from_module = ir_module.lookup_symbol(
            "inner_func", func_args=args_two
        )
        assert symbol_inner_from_module is None, "在模块级别不应该找到嵌套函数"

        # 在 outer_func 内部查找 inner_func
        outer_func_node = find_function_node(ir_module, "outer_func")
        symbol_inner = outer_func_node.lookup_symbol("inner_func", func_args=args_two)
        assert (
            symbol_inner is not None
        ), "在 outer_func 内应该能找到 inner_func(int, int)"
        assert symbol_inner.name == "inner_func"


class TestLookupSymbolNewInterface:
    """测试 lookup_symbol 的新接口（template_args 和 func_args 分离）"""

    def setup_method(self):
        """设置测试环境"""
        from mcpy.symbol_table import SymbolTable
        from mcpy.symbol_meta import TypeInfo, TypeKind, SymbolKind, Symbol, Signature
        from mcpy.template_param import TemplateParam

        self.symbol_table = SymbolTable()

        # 注册一些测试符号
        # 1. 模板类型符号：list[T]
        self.symbol_table.register_template_type(
            name="list",
            template_params=["T"],
            cpp_template="mc::array<{T}>",
            is_variadic=False,
        )

        # 2. 函数符号：max(T, T) -> T
        t_param = TemplateParam(name="T")
        max_sig = Signature(
            function_name="max",
            param_types=["T", "T"],
            return_type="T",
            template_params=["T"],
            template_params_detailed=[t_param],
        )
        max_symbol = Symbol(
            name="max",
            kind=SymbolKind.FUNCTION,
            type_info=TypeInfo(kind=TypeKind.FUNCTION, name="max"),
        )
        max_symbol.add_signature(max_sig)
        self.symbol_table.register_function_symbol(max_symbol)

    def test_lookup_type_with_template_args(self):
        """测试使用 template_args 查询类型"""
        from mcpy.symbol_meta import TypeInfo, TypeKind

        int_type = TypeInfo(kind=TypeKind.CLASS, name="int")

        # 新接口：查询 list[int]
        symbol = self.symbol_table.lookup_symbol("list", template_args=[int_type])

        assert symbol is not None
        assert symbol.name == "list[int]"
        assert symbol.kind == SymbolKind.CLASS
        assert symbol.type_info is not None
        assert symbol.type_info.template_base == "list"
        assert symbol.type_info.is_instantiated

    def test_lookup_function_with_func_args(self):
        """测试使用 func_args 查询函数"""
        from mcpy.symbol_meta import TypeInfo, TypeKind

        int_type = TypeInfo(kind=TypeKind.CLASS, name="int")

        # 新接口：查询 max(int, int)
        symbol = self.symbol_table.lookup_symbol("max", func_args=[int_type, int_type])

        assert symbol is not None
        assert symbol.name == "max"
        assert symbol.kind == SymbolKind.FUNCTION

    def test_backward_compatibility_type(self):
        """测试向后兼容：使用 args_types 查询类型"""
        from mcpy.symbol_meta import TypeInfo, TypeKind, SymbolKind

        int_type = TypeInfo(kind=TypeKind.CLASS, name="int")

        # 旧接口：查询 list[int]（指定 symbol_kinds）
        symbol = self.symbol_table.lookup_symbol(
            "list", template_args=[int_type], symbol_kinds=[SymbolKind.CLASS]
        )

        assert symbol is not None
        assert symbol.name == "list[int]"
        assert symbol.type_info and symbol.type_info.template_base == "list"

    def test_backward_compatibility_function(self):
        """测试向后兼容：使用 args_types 查询函数"""
        from mcpy.symbol_meta import TypeInfo, TypeKind, SymbolKind

        int_type = TypeInfo(kind=TypeKind.CLASS, name="int")

        # 旧接口：查询 max(int, int)（指定 symbol_kinds）
        symbol = self.symbol_table.lookup_symbol(
            "max", func_args=[int_type, int_type], symbol_kinds=[SymbolKind.FUNCTION]
        )

        assert symbol is not None
        assert symbol.name == "max"
